/*-------------------------------------------------------------------------
 *
 * fmgr.h
 *	  用于 Postgres 函数管理器和函数调用接口的定义。
 *
 * 此文件必须被所有定义或调用 fmgr 可调用函数的 Postgres 模块包含。
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/fmgr.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef FMGR_H
#define FMGR_H

/* 我们不想在这里包含 primnodes.h，因此做一些存根引用 */
typedef struct Node *fmNodePtr;
typedef struct Aggref *fmAggrefPtr;

/* 同样，避免在这里包含 execnodes.h */
typedef void (*fmExprContextCallbackFunction) (Datum arg);

/* 同样，避免在这里包含 stringinfo.h */
typedef struct StringInfoData *fmStringInfo;


/*
 * 所有可以被 fmgr 直接调用的函数必须具有此签名。
 * （其他函数可以通过使用具有此签名的处理程序来调用。）
 */

typedef struct FunctionCallInfoBaseData *FunctionCallInfo;

typedef Datum (*PGFunction) (FunctionCallInfo fcinfo);

/*
 * 该结构保存必须在通过 fmgr 调用函数之前查找的系统目录信息。
 * 如果同一函数要被多次调用，查找只需进行一次，并将
 * 信息结构保存以供重用。
 *
 * 请注意，fn_expr 实际上是关于参数的解析时确定的信息，
 * 而不是关于函数本身的信息。但把它存储在这里是方便的，
 * 而不是在 FunctionCallInfoBaseData 中，后者可能更逻辑上
 * 属于此处。
 *
 * fn_extra 可供被调用函数使用；所有其他字段应在结构创建后
 * 视为只读。
 */
typedef struct FmgrInfo
{
	PGFunction	fn_addr;		/* 指向要调用的函数或处理程序的指针 */
	Oid			fn_oid;			/* 函数的OID（如果有处理程序，则不是处理程序的OID） */
	short		fn_nargs;		/* 输入参数的数量（0..FUNC_MAX_ARGS） */
	bool		fn_strict;		/* 函数是“严格”的（输入为NULL -> 输出为NULL） */
	bool		fn_retset;		/* 函数返回一个集合 */
	unsigned char fn_stats;		/* 如果track_functions > 此值，则收集统计信息 */
	void	   *fn_extra;		/* 处理程序使用的额外空间 */
	MemoryContext fn_mcxt;		/* 存储fn_extra的内存上下文 */
	fmNodePtr	fn_expr;		/* 调用的表达式解析树，或NULL */
} FmgrInfo;

/*
 * 这个结构是实际传递给fmgr调用的函数的数据。
 *
 * 被调用的函数预期会设置isnull，并可能设置resultinfo或者
 * resultinfo指向的任何字段。它不应该更改其他字段。
 * （特别是，修改参数数组是个坏主意，因为一些调用者假设
 * 它们可以使用相同的参数进行重新调用。）
 *
 * 注意必须提供足够的参数空间，可以通过在动态分配中使用
 * SizeForFunctionCallInfo()，或通过在栈分配中使用
 * LOCAL_FCINFO()。
 *
 * 这个结构被命名为*BaseData，而不是*Data，以打破
 * 分配FunctionCallInfoData自身的预v12代码，因为这通常会
 * 无声地破坏旧代码，因为没有提供参数的空间。
 */
typedef struct FunctionCallInfoBaseData
{
	FmgrInfo   *flinfo;			/* 用于此次调用的查找信息的指针 */
	fmNodePtr	context;		/* 传递有关调用上下文的信息 */
	fmNodePtr	resultinfo;		/* 传递或返回有关结果的额外信息 */
	Oid			fncollation;	/* 函数使用的排序规则 */
#define FIELDNO_FUNCTIONCALLINFODATA_ISNULL 4
	bool		isnull;			/* 如果结果为NULL，函数必须设置为true */
	short		nargs;			/* 实际传递的参数数量 */
#define FIELDNO_FUNCTIONCALLINFODATA_ARGS 6
	NullableDatum args[FLEXIBLE_ARRAY_MEMBER];
} FunctionCallInfoBaseData;

/*
 * 为具有足够`nargs`参数空间的FunctionCallInfoBaseData结构所需的空间。
 */
#define SizeForFunctionCallInfo(nargs) \
	(offsetof(FunctionCallInfoBaseData, args) + \
	 sizeof(NullableDatum) * (nargs))

/*
 * 该宏确保`name`指向一个栈分配的
 * FunctionCallInfoBaseData结构，并拥有足够的`nargs`参数空间。
 */
#define LOCAL_FCINFO(name, nargs) \
	/* 使用与FunctionCallInfoBaseData的联合体以保证对齐 */ \
	union \
	{ \
		FunctionCallInfoBaseData fcinfo; \
		/* 确保为nargs参数提供足够的空间 */ \
		char fcinfo_data[SizeForFunctionCallInfo(nargs)]; \
	} name##data; \
	FunctionCallInfo name = &name##data.fcinfo

/*
 * 此例程填充FmgrInfo结构，给定要调用的函数OID。
 */
extern void fmgr_info(Oid functionId, FmgrInfo *finfo);

/*
 * 相同，当FmgrInfo结构在比CurrentMemoryContext更长效的内存上下文中时。
 * 指定的上下文将被设置为fn_mcxt，并用于保存finfo的所有子数据。
 */
extern void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo,
						  MemoryContext mcxt);

/* 设置fn_expr字段的便利宏 */
#define fmgr_info_set_expr(expr, finfo) \
	((finfo)->fn_expr = (expr))

/*
 * 复制一个FmgrInfo结构
 */
extern void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo,
						   MemoryContext destcxt);

extern void fmgr_symbol(Oid functionId, char **mod, char **fn);

/*
 * 该宏初始化FunctionCallInfoBaseData的所有字段，除了args[]数组。
 */
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo) \
	do { \
		(Fcinfo).flinfo = (Flinfo); \
		(Fcinfo).context = (Context); \
		(Fcinfo).resultinfo = (Resultinfo); \
		(Fcinfo).fncollation = (Collation); \
		(Fcinfo).isnull = false; \
		(Fcinfo).nargs = (Nargs); \
	} while (0)

/*
 * 该宏在给定填充的FunctionCallInfoBaseData结构时调用一个函数。
 * 宏的结果是返回的Datum --- 但请注意，调用者必须仍然检查fcinfo->isnull！
 * 此外，如果函数是严格的，调用者有责任确保在调用前没有传入null参数。
 *
 * 一些代码在不重新执行InitFunctionCallInfoData的情况下执行多个调用，
 * 可能会改变参数值。这是可以的，但请确保在每次调用前重置
 * fcinfo->isnull标志，因为被调用者被允许假设该值开始时为false。
 */
#define FunctionCallInvoke(fcinfo)	((* (fcinfo)->flinfo->fn_addr) (fcinfo))


/*---------------------------------------------------------------------------
 *  支持宏以简化编写fmgr兼容函数
 *
 * 用C代码编写的fmgr兼容函数应声明为
 *
 *      Datum
 *      function_name(PG_FUNCTION_ARGS)
 *      {
 *          ...
 *      }
 *
 * 它应使用适当的PG_GETARG_xxx宏访问其参数，
 * 并应使用PG_RETURN_xxx返回其结果。
 *
 *-------------------------------------------------------------------------
 */

/* fmgr兼容函数的标准参数列表 */
#define PG_FUNCTION_ARGS	FunctionCallInfo fcinfo

/*
 * 获取排序函数应使用的。
 */
#define PG_GET_COLLATION()	(fcinfo->fncollation)

/*
 * 获取传递给函数的参数数量。
 */
#define PG_NARGS() (fcinfo->nargs)

/*
 * 如果函数在 pg_proc 中未标记为 "proisstrict"，则必须使用此宏检查
 * 空参数。不要尝试获取空参数！
 */
#define PG_ARGISNULL(n)  (fcinfo->args[n].isnull)

/*
 * 支持获取可烘焙数据类型（所有都是 varlena 类型）的去烘焙副本。
 * pg_detoast_datum() 给您输入数据（如果未烘焙）或使用 palloc() 分配的去烘焙副本。
 * pg_detoast_datum_copy() 始终给您一个 palloc'd 副本 --- 如果需要可修改的输入副本，请使用它。
 * 调用者应在必要时先检查空输入。
 *
 * pg_detoast_datum_packed() 将返回未修改的打包（1 字节头）数据。
 * 它仍然会扩展外部烘焙或压缩的数据。
 * 可使用 VARSIZE_ANY() 和 VARDATA_ANY() 访问结果数据
 * （在这些宏中要小心多次评估！）
 *
 * 在对数据对齐无感知的消费者中，调用 PG_DETOAST_DATUM_PACKED()，
 * VARDATA_ANY()，VARSIZE_ANY() 和 VARSIZE_ANY_EXHDR()。在其他地方，调用
 * PG_DETOAST_DATUM()，VARDATA() 和 VARSIZE()。直接获取表示数据布局的
 * 结构中的 int16，int32 或更宽字段需要对齐数据。
 * memcpy() 对齐无感知，正如大多数操作在数据类型上，例如文本，其布局结构仅包含 char 字段。
 *
 * 注意：如果这些可以是宏就好了，但我没有看到这样做的办法
 * 而不多次评估参数，这是不可接受的。
 */
extern struct varlena *pg_detoast_datum(struct varlena *datum);
extern struct varlena *pg_detoast_datum_copy(struct varlena *datum);
extern struct varlena *pg_detoast_datum_slice(struct varlena *datum,
											  int32 first, int32 count);
extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);

#define PG_DETOAST_DATUM(datum) \
	pg_detoast_datum((struct varlena *) DatumGetPointer(datum))
#define PG_DETOAST_DATUM_COPY(datum) \
	pg_detoast_datum_copy((struct varlena *) DatumGetPointer(datum))
#define PG_DETOAST_DATUM_SLICE(datum,f,c) \
		pg_detoast_datum_slice((struct varlena *) DatumGetPointer(datum), \
		(int32) (f), (int32) (c))
/* 警告 -- 未对齐指针 */
#define PG_DETOAST_DATUM_PACKED(datum) \
	pg_detoast_datum_packed((struct varlena *) DatumGetPointer(datum))

/*
 * 支持清理输入的去烘焙副本。此功能仅应用于引用传递数据类型，
 * 通常仅应用于可烘焙类型。如果给定指针与原始参数不同，
 * 假设它是一个 palloc'd 去烘焙副本，并进行 pfree。
 * 注意：大多数可烘焙类型的函数不必担心这一点，
 * 但我们目前要求索引的支持函数不要泄漏内存。
 */
#define PG_FREE_IF_COPY(ptr,n) \
	do { \
		if ((Pointer) (ptr) != PG_GETARG_POINTER(n)) \
			pfree(ptr); \
	} while (0)

/* 用于获取标准类型参数的宏 */

#define PG_GETARG_DATUM(n)	 (fcinfo->args[n].value)
#define PG_GETARG_INT32(n)	 DatumGetInt32(PG_GETARG_DATUM(n))
#define PG_GETARG_UINT32(n)  DatumGetUInt32(PG_GETARG_DATUM(n))
#define PG_GETARG_INT16(n)	 DatumGetInt16(PG_GETARG_DATUM(n))
#define PG_GETARG_UINT16(n)  DatumGetUInt16(PG_GETARG_DATUM(n))
#define PG_GETARG_CHAR(n)	 DatumGetChar(PG_GETARG_DATUM(n))
#define PG_GETARG_BOOL(n)	 DatumGetBool(PG_GETARG_DATUM(n))
#define PG_GETARG_OID(n)	 DatumGetObjectId(PG_GETARG_DATUM(n))
#define PG_GETARG_POINTER(n) DatumGetPointer(PG_GETARG_DATUM(n))
#define PG_GETARG_CSTRING(n) DatumGetCString(PG_GETARG_DATUM(n))
#define PG_GETARG_NAME(n)	 DatumGetName(PG_GETARG_DATUM(n))
#define PG_GETARG_TRANSACTIONID(n)	DatumGetTransactionId(PG_GETARG_DATUM(n))
/* 这些宏隐藏了数据类型的引用传递性： */
#define PG_GETARG_FLOAT4(n)  DatumGetFloat4(PG_GETARG_DATUM(n))
#define PG_GETARG_FLOAT8(n)  DatumGetFloat8(PG_GETARG_DATUM(n))
#define PG_GETARG_INT64(n)	 DatumGetInt64(PG_GETARG_DATUM(n))
/* 如果您想要原始的、可能已烘焙的输入数据，请使用此宏： */
#define PG_GETARG_RAW_VARLENA_P(n)	((struct varlena *) PG_GETARG_POINTER(n))
/* 如果您想要去烘焙的输入数据，请使用此宏： */
#define PG_GETARG_VARLENA_P(n) PG_DETOAST_DATUM(PG_GETARG_DATUM(n))
/* 如果您可以处理 1 字节头数据，请使用此宏： */
#define PG_GETARG_VARLENA_PP(n) PG_DETOAST_DATUM_PACKED(PG_GETARG_DATUM(n))
/* 对于 varlena 类型，DatumGetFoo 宏通常看起来像这样： */
#define DatumGetByteaPP(X)			((bytea *) PG_DETOAST_DATUM_PACKED(X))
#define DatumGetTextPP(X)			((text *) PG_DETOAST_DATUM_PACKED(X))
#define DatumGetBpCharPP(X)			((BpChar *) PG_DETOAST_DATUM_PACKED(X))
#define DatumGetVarCharPP(X)		((VarChar *) PG_DETOAST_DATUM_PACKED(X))
#define DatumGetHeapTupleHeader(X)	((HeapTupleHeader) PG_DETOAST_DATUM(X))
/* 我们还提供返回可以写入副本的变体 */
#define DatumGetByteaPCopy(X)		((bytea *) PG_DETOAST_DATUM_COPY(X))
#define DatumGetTextPCopy(X)		((text *) PG_DETOAST_DATUM_COPY(X))
#define DatumGetBpCharPCopy(X)		((BpChar *) PG_DETOAST_DATUM_COPY(X))
#define DatumGetVarCharPCopy(X)		((VarChar *) PG_DETOAST_DATUM_COPY(X))
#define DatumGetHeapTupleHeaderCopy(X)	((HeapTupleHeader) PG_DETOAST_DATUM_COPY(X))
/* 返回从位置 m 开始的 n 字节的变体 */
#define DatumGetByteaPSlice(X,m,n)	((bytea *) PG_DETOAST_DATUM_SLICE(X,m,n))
#define DatumGetTextPSlice(X,m,n)	((text *) PG_DETOAST_DATUM_SLICE(X,m,n))
#define DatumGetBpCharPSlice(X,m,n) ((BpChar *) PG_DETOAST_DATUM_SLICE(X,m,n))
#define DatumGetVarCharPSlice(X,m,n) ((VarChar *) PG_DETOAST_DATUM_SLICE(X,m,n))
/* 对于 varlena 类型，GETARG 宏通常看起来像这样： */
#define PG_GETARG_BYTEA_PP(n)		DatumGetByteaPP(PG_GETARG_DATUM(n))
#define PG_GETARG_TEXT_PP(n)		DatumGetTextPP(PG_GETARG_DATUM(n))
#define PG_GETARG_BPCHAR_PP(n)		DatumGetBpCharPP(PG_GETARG_DATUM(n))
#define PG_GETARG_VARCHAR_PP(n)		DatumGetVarCharPP(PG_GETARG_DATUM(n))
#define PG_GETARG_HEAPTUPLEHEADER(n)	DatumGetHeapTupleHeader(PG_GETARG_DATUM(n))
/* 我们还提供返回可以写入副本的变体 */
#define PG_GETARG_BYTEA_P_COPY(n)	DatumGetByteaPCopy(PG_GETARG_DATUM(n))
#define PG_GETARG_TEXT_P_COPY(n)	DatumGetTextPCopy(PG_GETARG_DATUM(n))
#define PG_GETARG_BPCHAR_P_COPY(n)	DatumGetBpCharPCopy(PG_GETARG_DATUM(n))
#define PG_GETARG_VARCHAR_P_COPY(n) DatumGetVarCharPCopy(PG_GETARG_DATUM(n))
#define PG_GETARG_HEAPTUPLEHEADER_COPY(n)	DatumGetHeapTupleHeaderCopy(PG_GETARG_DATUM(n))
/* 还有一个从位置 a 开始的 b 字节切片 —— 也可以写入 */
#define PG_GETARG_BYTEA_P_SLICE(n,a,b) DatumGetByteaPSlice(PG_GETARG_DATUM(n),a,b)
#define PG_GETARG_TEXT_P_SLICE(n,a,b)  DatumGetTextPSlice(PG_GETARG_DATUM(n),a,b)
#define PG_GETARG_BPCHAR_P_SLICE(n,a,b) DatumGetBpCharPSlice(PG_GETARG_DATUM(n),a,b)
#define PG_GETARG_VARCHAR_P_SLICE(n,a,b) DatumGetVarCharPSlice(PG_GETARG_DATUM(n),a,b)
/*
 * 过时的变体，保证返回值的 INT 对齐。
 * 对这些特定类型的少数操作需要对齐，主要是将 VARDATA 指针强制转换为 int16[] 之类的操作。
 * 大多数代码应使用 ...PP(X) 对应函数。尽管如此，这些在 PostgreSQL 8.3 引入的
 * ...PP(X) 变体之前的代码中仍然频繁出现。
 */
#define DatumGetByteaP(X)			((bytea *) PG_DETOAST_DATUM(X))
#define DatumGetTextP(X)			((text *) PG_DETOAST_DATUM(X))
#define DatumGetBpCharP(X)			((BpChar *) PG_DETOAST_DATUM(X))
#define DatumGetVarCharP(X)			((VarChar *) PG_DETOAST_DATUM(X))
#define PG_GETARG_BYTEA_P(n)		DatumGetByteaP(PG_GETARG_DATUM(n))
#define PG_GETARG_TEXT_P(n)			DatumGetTextP(PG_GETARG_DATUM(n))
#define PG_GETARG_BPCHAR_P(n)		DatumGetBpCharP(PG_GETARG_DATUM(n))
#define PG_GETARG_VARCHAR_P(n)		DatumGetVarCharP(PG_GETARG_DATUM(n))

/* 要从 opclass 支持函数访问选项，请使用此宏： */
#define PG_HAS_OPCLASS_OPTIONS()	has_fn_opclass_options(fcinfo->flinfo)
#define PG_GET_OPCLASS_OPTIONS()	get_fn_opclass_options(fcinfo->flinfo)

/* 要返回 NULL，请执行以下操作： */
#define PG_RETURN_NULL()  \
	do { fcinfo->isnull = true; return (Datum) 0; } while (0)

/* 一些内部函数返回 void（这与 NULL 不同！） */
#define PG_RETURN_VOID()	 return (Datum) 0

/* 用于返回标准类型结果的宏 */

#define PG_RETURN_DATUM(x)	 return (x)
#define PG_RETURN_INT32(x)	 return Int32GetDatum(x)
#define PG_RETURN_UINT32(x)  return UInt32GetDatum(x)
#define PG_RETURN_INT16(x)	 return Int16GetDatum(x)
#define PG_RETURN_UINT16(x)  return UInt16GetDatum(x)
#define PG_RETURN_CHAR(x)	 return CharGetDatum(x)
#define PG_RETURN_BOOL(x)	 return BoolGetDatum(x)
#define PG_RETURN_OID(x)	 return ObjectIdGetDatum(x)
#define PG_RETURN_POINTER(x) return PointerGetDatum(x)
#define PG_RETURN_CSTRING(x) return CStringGetDatum(x)
#define PG_RETURN_NAME(x)	 return NameGetDatum(x)
#define PG_RETURN_TRANSACTIONID(x)	return TransactionIdGetDatum(x)
/* 这些宏隐藏了数据类型的引用传递性： */
#define PG_RETURN_FLOAT4(x)  return Float4GetDatum(x)
#define PG_RETURN_FLOAT8(x)  return Float8GetDatum(x)
#define PG_RETURN_INT64(x)	 return Int64GetDatum(x)
#define PG_RETURN_UINT64(x)  return UInt64GetDatum(x)
/* 对于其他引用传递类型，RETURN 宏通常看起来像这样： */
#define PG_RETURN_BYTEA_P(x)   PG_RETURN_POINTER(x)
#define PG_RETURN_TEXT_P(x)    PG_RETURN_POINTER(x)
#define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
#define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
#define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)


/*-------------------------------------------------------------------------
 *		支持检测动态加载函数的调用约定
 *
 * 动态加载的函数当前只能使用版本 1（"新样式"）调用约定。
 * 不再支持版本 0（"旧样式"）。版本 1 是此头文件中定义的调用约定，
 * 必须伴随宏调用
 *
 *		PG_FUNCTION_INFO_V1(function_name);
 *
 * 注意，内部函数不需要此装饰，因为它们被假定为版本 1。
 *
 *-------------------------------------------------------------------------
 */

typedef struct
{
	int			api_version;	/* 指定调用约定版本号 */
	/* 可能会在以后添加更多字段，以支持版本号 > 1。 */
} Pg_finfo_record;

/* info 函数的预期签名 */
typedef const Pg_finfo_record *(*PGFInfoFunction) (void);


/*
 *宏用于构建与给定函数名称相关的信息函数。
 *
 *为方便起见，还提供了给定函数名称的“extern”声明，以便C函数的编写者不必写这个。
 *
 *在Windows上，函数和信息函数必须被导出。我们的正常构建流程通过.DEF文件或--export-all-symbols处理这件事。
 *使用不同构建流程的模块作者可能需要手动声明函数PGDLLEXPORT。我们在这里自动执行这一步，因为作者不需要显式了解它。
 */
#define PG_FUNCTION_INFO_V1(funcname) \
extern Datum funcname(PG_FUNCTION_ARGS); \
extern PGDLLEXPORT const Pg_finfo_record * CppConcat(pg_finfo_,funcname)(void); \
const Pg_finfo_record * \
CppConcat(pg_finfo_,funcname) (void) \
{ \
	static const Pg_finfo_record my_finfo = { 1 }; \
	return &my_finfo; \
} \
extern int no_such_variable


/*-------------------------------------------------------------------------
 *		支持验证加载模块的后端兼容性
 *
 * 我们要求动态加载的模块包含宏调用
 *		PG_MODULE_MAGIC;
 * 以便我们能够检查明显的不兼容性，例如为不同的主要PostgreSQL版本编译。
 *
 * 要与不支持此功能的PostgreSQL版本编译，您可以在其周围放置#ifdef/#endif测试。
 * 请注意，在多源文件模块中，宏调用只能出现一次。
 *
 * 魔法块中包含的具体项目旨在是可自定义的，并且特别容易在与其他值编译时破坏动态加载的模块。此外，长度字段
 * 可用于检测定义变更。
 *
 * 注意：我们使用memcmp()比较魔法块，因此其中最好没有任何对齐填充字节。
 *
 * 注意：在更改魔法块的内容时，请确保调整dfmgr.c中的incompatible_module_error()函数。
 *-------------------------------------------------------------------------
 */

/* 魔法块结构的定义 */
typedef struct
{
	int			len;			/* sizeof(this struct) */
	int			version;		/* PostgreSQL 主要版本 */
	int			funcmaxargs;	/* FUNC_MAX_ARGS */
	int			indexmaxkeys;	/* INDEX_MAX_KEYS */
	int			namedatalen;	/* NAMEDATALEN */
	int			float8byval;	/* FLOAT8PASSBYVAL */
	char		abi_extra[32];	/* 请参见 pg_config_manual.h */
} Pg_magic_struct;

/* 实际数据块内容 */
#define PG_MODULE_MAGIC_DATA \
{ \
	sizeof(Pg_magic_struct), \
	PG_VERSION_NUM / 100, \
	FUNC_MAX_ARGS, \
	INDEX_MAX_KEYS, \
	NAMEDATALEN, \
	FLOAT8PASSBYVAL, \
	FMGR_ABI_EXTRA, \
}

StaticAssertDecl(sizeof(FMGR_ABI_EXTRA) <= sizeof(((Pg_magic_struct *) 0)->abi_extra),
				 "FMGR_ABI_EXTRA too long");

/*
 * 声明模块魔法函数。它需要是一个函数，因为后端的 dlsym
 * 只保证在函数上有效，而不是数据
 */
typedef const Pg_magic_struct *(*PGModuleMagicFunction) (void);

#define PG_MAGIC_FUNCTION_NAME Pg_magic_func
#define PG_MAGIC_FUNCTION_NAME_STRING "Pg_magic_func"

#define PG_MODULE_MAGIC \
extern PGDLLEXPORT const Pg_magic_struct *PG_MAGIC_FUNCTION_NAME(void); \
const Pg_magic_struct * \
PG_MAGIC_FUNCTION_NAME(void) \
{ \
	static const Pg_magic_struct Pg_magic_data = PG_MODULE_MAGIC_DATA; \
	return &Pg_magic_data; \
} \
extern int no_such_variable


/*-------------------------------------------------------------------------
 *		支持 fmgr 兼容函数调用者的例程和宏
 *-------------------------------------------------------------------------
 */

/* 这些用于调用特定命名函数并直接计算参数列表。注意，参数和结果
 * 都不允许是 NULL。此外，函数不能是需要
 * 查看 FmgrInfo 的，因为不会有任何 FmgrInfo。
 */
extern Datum DirectFunctionCall1Coll(PGFunction func, Oid collation,
									 Datum arg1);
extern Datum DirectFunctionCall2Coll(PGFunction func, Oid collation,
									 Datum arg1, Datum arg2);
extern Datum DirectFunctionCall3Coll(PGFunction func, Oid collation,
									 Datum arg1, Datum arg2,
									 Datum arg3);
extern Datum DirectFunctionCall4Coll(PGFunction func, Oid collation,
									 Datum arg1, Datum arg2,
									 Datum arg3, Datum arg4);
extern Datum DirectFunctionCall5Coll(PGFunction func, Oid collation,
									 Datum arg1, Datum arg2,
									 Datum arg3, Datum arg4, Datum arg5);
extern Datum DirectFunctionCall6Coll(PGFunction func, Oid collation,
									 Datum arg1, Datum arg2,
									 Datum arg3, Datum arg4, Datum arg5,
									 Datum arg6);
extern Datum DirectFunctionCall7Coll(PGFunction func, Oid collation,
									 Datum arg1, Datum arg2,
									 Datum arg3, Datum arg4, Datum arg5,
									 Datum arg6, Datum arg7);
extern Datum DirectFunctionCall8Coll(PGFunction func, Oid collation,
									 Datum arg1, Datum arg2,
									 Datum arg3, Datum arg4, Datum arg5,
									 Datum arg6, Datum arg7, Datum arg8);
extern Datum DirectFunctionCall9Coll(PGFunction func, Oid collation,
									 Datum arg1, Datum arg2,
									 Datum arg3, Datum arg4, Datum arg5,
									 Datum arg6, Datum arg7, Datum arg8,
									 Datum arg9);

/*
 * 这些函数的工作方式类似于DirectFunctionCall函数，不同之处在于它们使用flinfo参数来初始化调用的fcinfo。
 * 推荐被调用者仅使用fn_extra和fn_mcxt字段，因为其他字段通常会描述调用函数而不是被调用者。反之，被调用的函数不应该使用fn_extra，除非其使用与被调用者的兼容。
 */
extern Datum CallerFInfoFunctionCall1(PGFunction func, FmgrInfo *flinfo,
									  Oid collation, Datum arg1);
extern Datum CallerFInfoFunctionCall2(PGFunction func, FmgrInfo *flinfo,
									  Oid collation, Datum arg1, Datum arg2);

/* 这些用于调用先前查找的函数并直接计算参数列表。注意，参数和结果
 * 都不允许是 NULL。
 */
extern Datum FunctionCall0Coll(FmgrInfo *flinfo, Oid collation);
extern Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation,
							   Datum arg1);
extern Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation,
							   Datum arg1, Datum arg2);
extern Datum FunctionCall3Coll(FmgrInfo *flinfo, Oid collation,
							   Datum arg1, Datum arg2,
							   Datum arg3);
extern Datum FunctionCall4Coll(FmgrInfo *flinfo, Oid collation,
							   Datum arg1, Datum arg2,
							   Datum arg3, Datum arg4);
extern Datum FunctionCall5Coll(FmgrInfo *flinfo, Oid collation,
							   Datum arg1, Datum arg2,
							   Datum arg3, Datum arg4, Datum arg5);
extern Datum FunctionCall6Coll(FmgrInfo *flinfo, Oid collation,
							   Datum arg1, Datum arg2,
							   Datum arg3, Datum arg4, Datum arg5,
							   Datum arg6);
extern Datum FunctionCall7Coll(FmgrInfo *flinfo, Oid collation,
							   Datum arg1, Datum arg2,
							   Datum arg3, Datum arg4, Datum arg5,
							   Datum arg6, Datum arg7);
extern Datum FunctionCall8Coll(FmgrInfo *flinfo, Oid collation,
							   Datum arg1, Datum arg2,
							   Datum arg3, Datum arg4, Datum arg5,
							   Datum arg6, Datum arg7, Datum arg8);
extern Datum FunctionCall9Coll(FmgrInfo *flinfo, Oid collation,
							   Datum arg1, Datum arg2,
							   Datum arg3, Datum arg4, Datum arg5,
							   Datum arg6, Datum arg7, Datum arg8,
							   Datum arg9);

/* 这些是用于以 OID 标识的函数调用的，具有直接计算的参数列表。注意，参数和结果都不允许为 NULL。这实际上是 fmgr_info() 后接 FunctionCallN()。如果同一个函数需要被多次调用，则只需进行一次 fmgr_info()，然后使用 FunctionCallN()。 */
extern Datum OidFunctionCall0Coll(Oid functionId, Oid collation);
extern Datum OidFunctionCall1Coll(Oid functionId, Oid collation,
								  Datum arg1);
extern Datum OidFunctionCall2Coll(Oid functionId, Oid collation,
								  Datum arg1, Datum arg2);
extern Datum OidFunctionCall3Coll(Oid functionId, Oid collation,
								  Datum arg1, Datum arg2,
								  Datum arg3);
extern Datum OidFunctionCall4Coll(Oid functionId, Oid collation,
								  Datum arg1, Datum arg2,
								  Datum arg3, Datum arg4);
extern Datum OidFunctionCall5Coll(Oid functionId, Oid collation,
								  Datum arg1, Datum arg2,
								  Datum arg3, Datum arg4, Datum arg5);
extern Datum OidFunctionCall6Coll(Oid functionId, Oid collation,
								  Datum arg1, Datum arg2,
								  Datum arg3, Datum arg4, Datum arg5,
								  Datum arg6);
extern Datum OidFunctionCall7Coll(Oid functionId, Oid collation,
								  Datum arg1, Datum arg2,
								  Datum arg3, Datum arg4, Datum arg5,
								  Datum arg6, Datum arg7);
extern Datum OidFunctionCall8Coll(Oid functionId, Oid collation,
								  Datum arg1, Datum arg2,
								  Datum arg3, Datum arg4, Datum arg5,
								  Datum arg6, Datum arg7, Datum arg8);
extern Datum OidFunctionCall9Coll(Oid functionId, Oid collation,
								  Datum arg1, Datum arg2,
								  Datum arg3, Datum arg4, Datum arg5,
								  Datum arg6, Datum arg7, Datum arg8,
								  Datum arg9);

/* 这些宏允许省略排序参数（默认为 InvalidOid，即无排序）。它们主要是为了源代码的向后兼容性。 */
#define DirectFunctionCall1(func, arg1) \
	DirectFunctionCall1Coll(func, InvalidOid, arg1)
#define DirectFunctionCall2(func, arg1, arg2) \
	DirectFunctionCall2Coll(func, InvalidOid, arg1, arg2)
#define DirectFunctionCall3(func, arg1, arg2, arg3) \
	DirectFunctionCall3Coll(func, InvalidOid, arg1, arg2, arg3)
#define DirectFunctionCall4(func, arg1, arg2, arg3, arg4) \
	DirectFunctionCall4Coll(func, InvalidOid, arg1, arg2, arg3, arg4)
#define DirectFunctionCall5(func, arg1, arg2, arg3, arg4, arg5) \
	DirectFunctionCall5Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5)
#define DirectFunctionCall6(func, arg1, arg2, arg3, arg4, arg5, arg6) \
	DirectFunctionCall6Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6)
#define DirectFunctionCall7(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
	DirectFunctionCall7Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
#define DirectFunctionCall8(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
	DirectFunctionCall8Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
#define DirectFunctionCall9(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \
	DirectFunctionCall9Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
#define FunctionCall1(flinfo, arg1) \
	FunctionCall1Coll(flinfo, InvalidOid, arg1)
#define FunctionCall2(flinfo, arg1, arg2) \
	FunctionCall2Coll(flinfo, InvalidOid, arg1, arg2)
#define FunctionCall3(flinfo, arg1, arg2, arg3) \
	FunctionCall3Coll(flinfo, InvalidOid, arg1, arg2, arg3)
#define FunctionCall4(flinfo, arg1, arg2, arg3, arg4) \
	FunctionCall4Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4)
#define FunctionCall5(flinfo, arg1, arg2, arg3, arg4, arg5) \
	FunctionCall5Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5)
#define FunctionCall6(flinfo, arg1, arg2, arg3, arg4, arg5, arg6) \
	FunctionCall6Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6)
#define FunctionCall7(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
	FunctionCall7Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
#define FunctionCall8(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
	FunctionCall8Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
#define FunctionCall9(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \
	FunctionCall9Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
#define OidFunctionCall0(functionId) \
	OidFunctionCall0Coll(functionId, InvalidOid)
#define OidFunctionCall1(functionId, arg1) \
	OidFunctionCall1Coll(functionId, InvalidOid, arg1)
#define OidFunctionCall2(functionId, arg1, arg2) \
	OidFunctionCall2Coll(functionId, InvalidOid, arg1, arg2)
#define OidFunctionCall3(functionId, arg1, arg2, arg3) \
	OidFunctionCall3Coll(functionId, InvalidOid, arg1, arg2, arg3)
#define OidFunctionCall4(functionId, arg1, arg2, arg3, arg4) \
	OidFunctionCall4Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4)
#define OidFunctionCall5(functionId, arg1, arg2, arg3, arg4, arg5) \
	OidFunctionCall5Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5)
#define OidFunctionCall6(functionId, arg1, arg2, arg3, arg4, arg5, arg6) \
	OidFunctionCall6Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6)
#define OidFunctionCall7(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
	OidFunctionCall7Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
#define OidFunctionCall8(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
	OidFunctionCall8Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
#define OidFunctionCall9(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \
	OidFunctionCall9Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)


/* 方便调用数据类型 I/O 函数的特殊情况。 */
extern Datum InputFunctionCall(FmgrInfo *flinfo, char *str,
							   Oid typioparam, int32 typmod);
extern Datum OidInputFunctionCall(Oid functionId, char *str,
								  Oid typioparam, int32 typmod);
extern char *OutputFunctionCall(FmgrInfo *flinfo, Datum val);
extern char *OidOutputFunctionCall(Oid functionId, Datum val);
extern Datum ReceiveFunctionCall(FmgrInfo *flinfo, fmStringInfo buf,
								 Oid typioparam, int32 typmod);
extern Datum OidReceiveFunctionCall(Oid functionId, fmStringInfo buf,
									Oid typioparam, int32 typmod);
extern bytea *SendFunctionCall(FmgrInfo *flinfo, Datum val);
extern bytea *OidSendFunctionCall(Oid functionId, Datum val);


/* 
 * fmgr.c 中的例程 
 */
extern const Pg_finfo_record *fetch_finfo_record(void *filehandle, const char *funcname);
extern Oid	fmgr_internal_function(const char *proname);
extern Oid	get_fn_expr_rettype(FmgrInfo *flinfo);
extern Oid	get_fn_expr_argtype(FmgrInfo *flinfo, int argnum);
extern Oid	get_call_expr_argtype(fmNodePtr expr, int argnum);
extern bool get_fn_expr_arg_stable(FmgrInfo *flinfo, int argnum);
extern bool get_call_expr_arg_stable(fmNodePtr expr, int argnum);
extern bool get_fn_expr_variadic(FmgrInfo *flinfo);
extern bytea *get_fn_opclass_options(FmgrInfo *flinfo);
extern bool has_fn_opclass_options(FmgrInfo *flinfo);
extern void set_fn_opclass_options(FmgrInfo *flinfo, bytea *options);
extern bool CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid);

/* 
 * dfmgr.c 中的例程 
 */
extern PGDLLIMPORT char *Dynamic_library_path;

extern void *load_external_function(const char *filename, const char *funcname,
									bool signalNotFound, void **filehandle);
extern void *lookup_external_function(void *filehandle, const char *funcname);
extern void load_file(const char *filename, bool restricted);
extern void **find_rendezvous_variable(const char *varName);
extern Size EstimateLibraryStateSpace(void);
extern void SerializeLibraryState(Size maxsize, char *start_address);
extern void RestoreLibraryState(char *start_address);

/* 
 * 支持聚合函数
 *
 * 这些实际上在 executor/nodeAgg.c 中，但我们在这里声明它们，因为
 * 整个目的是为了调用者不要与 nodeAgg 过于亲密。
 */

/* AggCheckCallContext 可以返回以下代码之一，或 0： */
#define AGG_CONTEXT_AGGREGATE	1	/* 常规聚合 */
#define AGG_CONTEXT_WINDOW		2	/* 窗口函数 */

extern int	AggCheckCallContext(FunctionCallInfo fcinfo,
								MemoryContext *aggcontext);
extern fmAggrefPtr AggGetAggref(FunctionCallInfo fcinfo);
extern MemoryContext AggGetTempMemoryContext(FunctionCallInfo fcinfo);
extern bool AggStateIsShared(FunctionCallInfo fcinfo);
extern void AggRegisterCallback(FunctionCallInfo fcinfo,
								fmExprContextCallbackFunction func,
								Datum arg);

/* 
 * 我们允许插件模块挂钩函数的入口/出口。这是为了支持可加载的安全策略模块，可能希望
 * 在函数入口或出口执行额外的特权检查，或执行其他内部簿记。为了实现这一点，这些模块必须
 * 能够支持正常的函数入口和出口，还能够捕获由于错误而中断的情况；它们还必须能够
 * 防止内联。
 */
typedef enum FmgrHookEventType
{
	FHET_START,
	FHET_END,
	FHET_ABORT
} FmgrHookEventType;

typedef bool (*needs_fmgr_hook_type) (Oid fn_oid);

typedef void (*fmgr_hook_type) (FmgrHookEventType event,
								FmgrInfo *flinfo, Datum *arg);

extern PGDLLIMPORT needs_fmgr_hook_type needs_fmgr_hook;
extern PGDLLIMPORT fmgr_hook_type fmgr_hook;

#define FmgrHookIsNeeded(fn_oid)							\
	(!needs_fmgr_hook ? false : (*needs_fmgr_hook)(fn_oid))

#endif							/* FMGR_H */
